﻿#region Librerias

using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using ESF.Data;
using ESF.General;
using ESF.MSExcel;
using iTextSharp.text.pdf;
using Leadtools;
using Leadtools.Barcode;
using Leadtools.Codecs;
using Leadtools.Forms;
using ESF.FileProcessing;

#endregion


namespace ESF.Indexing
{
	public class IndexMaker : BaseTaskManager
	{	
		#region Members

		private bool _UseBasicExcel;

		private string _SetPrefix;
		private string _ItemPrefix;
		private string _BarCodePrefixType;

		private string _DirectoryPath;

		private bool _OnlyFirstByFolder;

		private List<string> _ValidExtensions;

		private List<BarcodeSymbology> _FindBarcodeTypes;

		private DbReader R;

		private DbWriter W;

		private DataTable _PreviousAdvance;

		private bool _UseLeadtools;

		private bool _TakeOnlyFirst;

		private bool _DetectBarCodes;

		private FileSystemWatcher _FSW;

		private string _IndexName;

		#endregion


		#region Propiedades de solo lectura

		public string GeneratedExcelFileName { get { return Path.Combine (_DirectoryPath, "Index.xlsx"); } }

		#endregion


		#region FSW Events

		private void FSW_Changed(object sender, FileSystemEventArgs e)
		{
			DeleteExistent (e.FullPath);
			
			AddToIndex (new FileInfo (e.FullPath), null);
		}

		private void FSW_Created(object sender, FileSystemEventArgs e)
		{
			AddToIndex (new FileInfo (e.FullPath), null);
		}

		#endregion


		#region Database Methods

		public void ConvertDBToXLS ()
		{
			ConvertDBToXLS (null);
		}


		public void ConvertDBToXLS (ProcessHelper.ReportProgressDelegate pdelReportProgress)
		{
			DataTable results;

			DataRow [] tempRows = null;

			int rowIndex;

			bool isNewFolder;
			bool generalSetOK = true;
			bool generalItemOK = true;

			string lastSetValue = string.Empty;
			string generalSetOKMsg = string.Empty;

			string tempCodes;
			string [] tempCodesArray;
			string tempText;

			XlsWriter xlsWriter = null;

			int totalAdvance;

			string currentFolder = string.Empty;

			Dictionary<BarcodeSymbology, int> barCodesMaxCount;
			
			Dictionary<char, bool?> seqRes;
			Dictionary<char, List<string>> seqData;


			try
			{
				totalAdvance = GetTotalAdvance ();

				if (totalAdvance > 1000000)
				{
					throw new GenericInfoException (string.Format ("Hay {0} registros pero Excel 2007 solo soporta hasta un millon, operación cancelada", totalAdvance));
				}

				if (totalAdvance == 0)
				{
					throw new GenericInfoException (string.Format ("No Hay {0} registros para el indice {1}, operación cancelada", totalAdvance, _IndexName));
				}

				barCodesMaxCount = GetBarCodesMaxCountDB ();

				results = GetFilesTable ();

				Start (results.Rows.Count);

				using (xlsWriter = new XlsWriter (GeneratedExcelFileName, _UseBasicExcel))
				{
					xlsWriter.AddSheet ("Index");

					#region Encabezado
					
					xlsWriter.StartRow ();

						xlsWriter.AddColumn ("Carpeta Padre", 20);
						xlsWriter.AddColumn ("Carpeta", 60);
						xlsWriter.AddColumn ("# Archivos", 30);
						xlsWriter.AddColumn ("Sec Num Nom Archivo", 30);
						xlsWriter.AddColumn ("Nombre del Archivo", 80);
						xlsWriter.AddColumn ("Tamaño", 30, 3);
						xlsWriter.AddColumn ("Paginas", 10, 2);
						xlsWriter.AddColumn ("Fecha Modificación", 100);
						xlsWriter.AddColumn ("Enlace", 60);

						#region Columnas para cada valor leido de barcodes

						if (DataHelper.IsEmpty<BarcodeSymbology, int> (barCodesMaxCount))
						{
							xlsWriter.AddEmptyCell ();
							xlsWriter.AddEmptyCell ();
						}
						else
						{
							foreach (KeyValuePair <BarcodeSymbology, int> item in barCodesMaxCount)
							{
								for (int i = 1; i <= item.Value; i++)
								{
									xlsWriter.AddColumn (item.Key.ToString () + "_" + i, 30);
								}

								if (item.Key.ToString () == _BarCodePrefixType)
								{
									xlsWriter.AddColumn (_SetPrefix + " ?", 40);
									xlsWriter.AddColumn (_ItemPrefix + " ?", 40); 
								}
							}
						}

						#endregion
				
						xlsWriter.AddColumn ("Proc. (ms)", 30);
						xlsWriter.AddColumn ("Exceptions", 30);
								
					xlsWriter.CloseRow ();

					rowIndex = 0;

					#endregion

					foreach (DataRow item in results.Rows)
					{
						rowIndex ++;

						#region Hay cambio de folder

						if (currentFolder != item ["Folder"].ToString ())
						{
							isNewFolder = true;
						
							xlsWriter.StartRow ();

							currentFolder = item ["Folder"].ToString ();
						}
						else
						{
							isNewFolder = false;

							xlsWriter.StartRow (1);
						}

						#endregion

						xlsWriter.AddCell (item ["ParentFolder"].ToString ());
						xlsWriter.AddCell(currentFolder);

						#region Es Nuevo Folder

						if (isNewFolder)
						{
							tempRows = results.Select (string.Format ("Folder = '{0}'", currentFolder));

							xlsWriter.AddCell (item ["FolderFileCount"].ToString ());

							xlsWriter.AddCell(
								TextHelper.IsTextNumericSecuenced(
									DataHelper.GetStringVector(tempRows, "Name",
										(string pItem) => { return Path.GetFileNameWithoutExtension(pItem); }).ToArray()) == true ? "SI" : "NO");
						}
						else
						{
							xlsWriter.AddEmptyCell ();

							xlsWriter.AddEmptyCell();
						}

						#endregion

						xlsWriter.AddCell (item ["Name"].ToString ());
						xlsWriter.AddCell (TextHelper.ToStringBytes (Convert.ToInt32 (item ["Length"])));
						xlsWriter.AddCell (DataHelper.GetNullableInt (item, "PageCount"));
						xlsWriter.AddCell (DataHelper.GetNullableDateTime (item, "LastWriteDateTime"));
						
						xlsWriter.AddHyperLinkCell (item ["Name"].ToString (), new Uri (item ["FileName"].ToString ().Replace (_DirectoryPath, string.Empty), UriKind.Relative));
						

							foreach (BarcodeSymbology ft in _FindBarcodeTypes)
							{
								#region Codigos leidos 

								if (barCodesMaxCount.ContainsKey (ft))
								{
									tempCodes = item [ft.ToString () + "BarCodes"].ToString ();

									if (string.IsNullOrWhiteSpace (tempCodes))
									{
										for (int i = 0; i < barCodesMaxCount [ft]; i++)
										{
											xlsWriter.AddEmptyCell ();
										}
									}
									else
									{
										tempCodesArray = tempCodes.Split (',');

										for (int i = 0; i < barCodesMaxCount [ft] - tempCodesArray.Count (); i++)
										{
											xlsWriter.AddEmptyCell();
										}

										foreach (string barCode in tempCodesArray)
										{
											xlsWriter.AddCell (barCode);
										}
									}

								}

								#endregion
	

								if (ft.ToString () == _BarCodePrefixType)
								{
									if (isNewFolder)
									{
										HasMultipleSequencesOK (
											DataHelper.GetStringVector (tempRows, ft.ToString () + "BarCodes"),
											out seqRes, out seqData);

										// No hubo secuencias para analizar
										if (seqData.Count == 0)
										{
											xlsWriter.AddEmptyCell();
											xlsWriter.AddEmptyCell();
										}
										else
										{
											xlsWriter.AddCell (string.Format ("{0}: {1}", _SetPrefix, seqData [_ItemPrefix [0]].Count () == Convert.ToInt32 (item ["FolderFileCount"]) ? "OK" : "ER"));

											if (generalSetOK)
											{
												if (seqData [_SetPrefix [0]].Count () == 0)
												{
													generalSetOKMsg = string.Format ("Para el archivo {0} no fue detectado el codigo de barras para {1} por lo que el grupo esta incompleto", item ["FileName"], _SetPrefix);
													generalSetOK = false;
												}
												else
												{
													if (string.IsNullOrWhiteSpace (lastSetValue))
													{
														lastSetValue = seqData [_SetPrefix [0]].First ();
													}
													else if (TextHelper.IsTextNumericSecuenced (lastSetValue, seqData [_SetPrefix [0]].First ()) != true)
													{
														generalSetOKMsg = string.Format ("Para el archivo {0} el codigo de barras para {1} del archivo anterior es {2} y el suyo es {3} pero no es secuencial", item ["FileName"], _SetPrefix, lastSetValue, seqData [_SetPrefix [0]].First ());
														generalSetOK = false;
													}
													else
													{
														lastSetValue = seqData[_SetPrefix[0]].First();
													}
												}
											}


											tempText = string.Empty;

											foreach (var seq in seqRes.Where (i => i.Value != null))
											{
												tempText += string.Format ("{0}: {1}", seq.Key, (seq.Value.Value ? "SI" : "NO"));
											}

											if (generalItemOK && seqRes [_ItemPrefix [0]].Value != true)
											{
												generalItemOK = false;
											}

											xlsWriter.AddCell (tempText);
										}
									}
									else
									{
										xlsWriter.AddEmptyCell ();
										xlsWriter.AddEmptyCell();
									}
								}
							}
			
							xlsWriter.AddCell (Convert.ToInt32 (item ["ProcessingTimeMs"]));
							xlsWriter.AddCell (item ["Exception"].ToString ());

							IncrementReadyCount ();

							ReportProgress ();
						
						xlsWriter.CloseRow ();
					}

					if (!string.IsNullOrWhiteSpace (_SetPrefix))
					{
						xlsWriter.StartRow(); 
						xlsWriter.CloseRow();

						xlsWriter.StartRow();

							if (generalSetOK)
							{
								xlsWriter.AddCell (string.Format ("Los valores para el conjunto de {0} esta correcto en secuencia", _SetPrefix));
							}
							else
							{
								xlsWriter.AddCell (generalSetOKMsg);
							}

						xlsWriter.CloseRow();

						xlsWriter.StartRow();

							if (!generalItemOK)
							{
								xlsWriter.AddCell(string.Format("Los valores para las secuencias de archivo del tipo {0} no estan en orden o faltan elementos.", _SetPrefix));
							}

						xlsWriter.CloseRow();
					}
				
					xlsWriter.CloseSheet (false);
				}
			}
			catch (OperationCanceledException cex)
			{
				Log.Error(cex);
			}
			finally
			{
				Stop();
			}
		}

		/// <summary>
		/// Identifica por la primer letra el inicio de diferentes secuencias y las verifica
		/// </summary>
		public void HasMultipleSequencesOK (List<string> pBarCodesForSequences, out Dictionary<char, bool?> pSeqOK, out Dictionary<char, List<string>> pSeqData)
		{
			pSeqData = new Dictionary<char, List<string>>();

			pSeqOK = new Dictionary<char, bool?>();
			

			// Si esta vacio o lleno de vacios
			if (DataHelper.IsEmpty (pBarCodesForSequences) 
				|| (from S in pBarCodesForSequences where string.IsNullOrWhiteSpace (S) select S).Count () == pBarCodesForSequences.Count()) { return; }

			foreach (string item in pBarCodesForSequences.Where (p => !string.IsNullOrWhiteSpace (p)))
			{
				foreach (string itemCode in TextHelper.Split (',', item))
				{
					if (!pSeqData.ContainsKey(itemCode[0]))
					{
						pSeqData.Add(itemCode[0], new List<string>() { itemCode });
					}
					else
					{
						pSeqData[itemCode[0]].Add(itemCode);
					}
				}
			}


			foreach (KeyValuePair<char, List<string>> item in pSeqData)
			{
				pSeqOK.Add(item.Key, TextHelper.IsTextNumericSecuenced(item.Value.ToArray()));
			}
		}


		public bool ExistsFileRegister (FileInfo pFile)
		{
			if (DataHelper.IsEmpty (_PreviousAdvance))
			{
				return false;
			}

			if (ItemReadyCount < _PreviousAdvance.Rows.Count)
			{
				if (DataHelper.IsEmpty (_PreviousAdvance.Rows.Find (pFile.FullName)))
				{
					return false;
				}
			}

			//return true;

			IDbCommand cmd;

			DataRow data;


			cmd = R.CreateCommand ("SELECT ID, LastWriteDateTime FROM Indexer WHERE FileName = @pFileName AND IndexName = @pIndexName");
	
			W.AddParameter (cmd, "pIndexName", _IndexName);
			W.AddParameter (cmd, "pFileName", pFile.FullName);

			data = R.GetFirstRow (cmd);

			if (DataHelper.IsEmpty (data)) { return false; }

			 //Parece que no almacena detalles micro asi se garantiza evitar caer en una repeticion innecesaria
			/*if (((TimeSpan) (pFile.LastWriteTime - Convert.ToDateTime (data ["LastWriteDateTime"]))).TotalMilliseconds > 1000)
			{
				DeleteExistent (pFile.FullName);
				return false;
			}*/

			return true;
		}


		public void Register (IndexElement pItem)
		{
			IDbCommand cmd;

			long? ID;

			StringBuilder columns = new StringBuilder ();
			StringBuilder parameters = new StringBuilder ();
			

			if (pItem.BarCodes != null)
			{
				foreach (var item in pItem.BarCodes)
				{
					item.Value.Sort ();
				}
			}
			

			ProcessHelper.ReTryWhen (
			new Action (() =>
			{
				cmd = R.CreateCommand ("SELECT ID FROM Indexer WHERE FileName = @pFileName AND IndexName = @pIndexName");

				
				ID = R.GetScalar<long?> (cmd);


				cmd = W.CreateCommand ();


				#region Parametros

				if (pItem.BarCodes != null)
				{
					foreach (BarcodeSymbology key in pItem.BarCodes.Keys)
					{
						columns.AppendFormat(", {0}BarCodes, {0}BarCodes_Count ", key.ToString());
						parameters.AppendFormat(", @p{0}BarCodes, @p{0}BarCodes_Count", key.ToString());

						W.AddParameter(cmd, "p" + key + "BarCodes", string.Join(",", pItem.BarCodes[key].ToArray()));
						W.AddParameter(cmd, "p" + key + "BarCodes_Count", pItem.BarCodes[key].ToArray().Count ());
					}
				}

				#endregion


				if (ID != null)
				{
					IDbCommand temp = W.CreateSPCommand ("DELETE FROM Indexer WHERE ID = @pID");
					
					W.AddParameter(cmd, "pID", ID);

					W.Execute (temp);
				}


				cmd.CommandText = "INSERT INTO Indexer (IndexName, ParentFolder, Folder, [Name], FileName, [Length], PageCount, LastWriteDateTime, ProcessingTimeMs, Exception, FolderFileCount" + columns.ToString ()  + ")" +
					" VALUES (@pIndexName, @pParentFolder, @pFolder, @pName, @pFileName, @pLength, @pPageCount, @pLastWriteDateTime, @pProcessingTimeMs, @pException, @pFolderFileCount" + parameters.ToString ()  + ")";
				
				W.AddParameter (cmd, "pIndexName", _IndexName);
				W.AddParameter (cmd, "pParentFolder", pItem.FileInfo.Directory.Parent);
				W.AddParameter (cmd, "pFolder", pItem.FileInfo.DirectoryName);
				W.AddParameter (cmd, "pName", pItem.FileInfo.Name);
				W.AddParameter (cmd, "pFileName", pItem.FileInfo.FullName);
				W.AddParameter (cmd, "pLength", pItem.FileInfo.Length);
				W.AddParameter (cmd, "pPageCount", pItem.PageCount);
				W.AddParameter (cmd, "pLastWriteDateTime", pItem.FileInfo.LastWriteTime);
				W.AddParameter(cmd, "pProcessingTimeMs", pItem.ProcessingTimeMs);
				W.AddParameter(cmd, "pException", pItem.Exception == null ? null : pItem.Exception.Message);
				W.AddParameter(cmd, "pFolderFileCount", pItem.FolderFileCount);

				
				W.Execute (cmd);
			}),
			TryVal,
			2000);

		} 


		public static bool TryVal (Exception pEx, int pTryCount)
		{
			if (pEx.Message.ToUpper ().Contains ("lock"))
			{ 
				return true;
			}

			if (pTryCount <= 300)
			{
				return true;
			}

			return false;
		}


		public void DeleteResults ()
		{
			IDbCommand cmd;


			cmd = W.CreateCommand ("DELETE FROM Indexer WHERE IndexName = @pIndexName");

			W.AddParameter (cmd, "pIndexName", _IndexName);

			W.Execute (cmd);
		}


		public int GetTotalAdvance ()
		{
			IDbCommand cmd;


			cmd = R.CreateCommand ("SELECT COUNT (ID) FROM Indexer WHERE IndexName = @pIndexName");

			W.AddParameter (cmd, "pIndexName", _IndexName);

			return R.GetScalar<int>(cmd);
		}


		public Dictionary<BarcodeSymbology, int> GetBarCodesMaxCountDB ()
		{
			Dictionary<BarcodeSymbology, int> result = new Dictionary<BarcodeSymbology,int> ();

			IDbCommand cmd;

			int? temp;


			cmd = R.CreateCommand ();
			
			W.AddParameter (cmd, "pIndexName", _IndexName);

			foreach (BarcodeSymbology key in _FindBarcodeTypes)
			{
				cmd.CommandText = string.Format ("SELECT MAX ({0}BarCodes_Count) FROM Indexer WHERE IndexName = @pIndexName", key);

				temp = R.GetScalar<int?>(cmd);

				if (temp != null && temp.Value > 0)
				{
					result.Add (key, temp.Value);
				}
			}

			return result;
		}


		public DataTable GetFilesTable ()
		{
			IDbCommand cmd;


			cmd = R.CreateCommand ("SELECT * FROM Indexer WHERE IndexName = @pIndexName ORDER BY [FileName]");

			W.AddParameter (cmd, "pIndexName", _IndexName);

			return R.GetFirstDataTable (cmd);
		}


		public void RenameExistent (string pOldFileName, string pFileName)
		{
			IDbCommand cmd;


			cmd = W.CreateCommand ("UPDATE Indexer SET FileName = @pFileName WHERE FileName = @pOldFileName AND IndexName = @pIndexName");

			W.AddParameter (cmd, "pFileName", pFileName);
			W.AddParameter (cmd, "pIndexName", _IndexName);
			W.AddParameter (cmd, "pOldFileName", pOldFileName);
			

			ProcessHelper.ReTryWhen (new Action (() => { W.Execute (cmd); }), TryVal, 3000);
		}


		public void DeleteExistent (string pFileName)
		{
			IDbCommand cmd;


			cmd = W.CreateCommand ("DELETE FROM Indexer WHERE FileName = @pFileName AND IndexName = @pIndexName");

			W.AddParameter (cmd, "pFileName", pFileName);
			W.AddParameter (cmd, "pIndexName", _IndexName);

			ProcessHelper.ReTryWhen (new Action (() => { W.Execute (cmd); }), TryVal, 3000);
		}

		#endregion


		#region Constructor

		public IndexMaker(ProcessHelper.ReportProgressDelegate pdelReportProgressDelegate = null)
			: base(pdelReportProgressDelegate) {}

		#endregion


		#region Get BarCodes

		private Dictionary<BarcodeSymbology, List<string>> GetBarCodesFromImage (ref Dictionary<BarcodeSymbology, List<string>> barCodes, string pFileName, out int pPageCount)
		{
			byte [] imageData;

			ImageFormat imageFormat;


			/*if (!IsValidExtension (Path.GetExtension (pFileName)))
			{
				pPageCount = -1; 
				return barCodes;
			}*/

			imageData = File.ReadAllBytes (pFileName);

			imageFormat = ImageHelper.GetImageFormat (imageData);

			if (imageFormat == ImageFormat.Tiff)
			{
				using (FileStream TIFS = ESF.General.FileHelper.GetFileStream (pFileName))
				{			
					MemoryStream jpgStream;
							
					TiffBitmapDecoder decoder = new TiffBitmapDecoder(TIFS, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);

					JpegBitmapEncoder encoder;
						

					pPageCount = decoder.Frames.Count;


					foreach (BitmapFrame m in decoder.Frames)
					{
						encoder = new JpegBitmapEncoder();

						encoder.Frames.Add (m);
						encoder.QualityLevel = 90;

						using (jpgStream = new MemoryStream ())
						{
							encoder.Save (jpgStream);

							jpgStream.Seek (0, SeekOrigin.Begin);

							GetBarCodes (ref barCodes, jpgStream.ToArray (), imageFormat);
						}

						if (_TakeOnlyFirst)
						{
							break;
						}
					}
				}
			}
			else
			{			
				pPageCount = 1;

				GetBarCodes (ref barCodes, imageData, imageFormat);
			}

			return barCodes;
		}


		private void GetBarCodes (ref Dictionary<BarcodeSymbology, List<string>> pBarCodes, byte [] pImageData, ImageFormat pImageFormat)
		{
			Image currentImage;
			
			
			if (_UseLeadtools)
			{
				GetBarCodesLEADTOOLS (ref pBarCodes, pImageData, pImageFormat);
				
				if (pBarCodes.Count == 0)
				{
					MemoryStream mem90Image;

					mem90Image = new MemoryStream ();

					currentImage = Image.FromStream (new MemoryStream (pImageData));
					currentImage.RotateFlip(RotateFlipType.Rotate90FlipNone);
					currentImage.Save(mem90Image, pImageFormat);  //TODO: Revisar formato
					mem90Image.Seek(0, SeekOrigin.Begin);

					GetBarCodesLEADTOOLS (ref pBarCodes, mem90Image.ToArray (), pImageFormat);

					mem90Image.Close();
					mem90Image.Dispose();
				}
			}			
		}


		private void GetBarCodesLEADTOOLS (ref Dictionary<BarcodeSymbology, List<string>> pBarCodes, byte [] pImageData, ImageFormat pImageFormat)
		{
			RasterImage newImage;
			BarcodeData[] dataArray;


			using(RasterCodecs codecs = new RasterCodecs())
			{
				newImage = codecs.Load (new MemoryStream (pImageData));
			}
			
			dataArray = new BarcodeEngine ().Reader.ReadBarcodes (newImage, LogicalRectangle.Empty, 0, _FindBarcodeTypes.ToArray ());

			if (!DataHelper.IsEmpty (dataArray))
			{
				foreach (BarcodeData d in dataArray)
				{	
					if (!pBarCodes.ContainsKey (d.Symbology))
					{
						pBarCodes.Add (d.Symbology, new List<string> ());
					}
					
					if (!pBarCodes [d.Symbology].Contains (d.Value))
					{
						pBarCodes [d.Symbology].Add (d.Value);
					}
				}
			}

			newImage.Dispose ();
		}
		

		private static void AddBarCodes (ref Dictionary<BarcodeSymbology, List<string>> pBarCodes, BarcodeSymbology pSymbology, string [] pItems)
		{
			if (DataHelper.IsEmpty (pItems))
			{
				return;
			}
			
			foreach (string item in pItems)
			{
				if (!pBarCodes.ContainsKey (pSymbology))
				{
					pBarCodes.Add (pSymbology, new List<string> ());
				}
					
				if (!pBarCodes [pSymbology].Contains (item))
				{
					pBarCodes [pSymbology].Add (item);
				}
			}
		}

		#endregion


		#region Funciones
		
		public override void Cancel ()
		{
			base.Cancel ();

			_FSW.EnableRaisingEvents = false;
		}


		public override void Stop ()
		{
			base.Stop ();

			if (_FSW != null)
			{
				_FSW.EnableRaisingEvents = false;
			}
		}


		public void Initialize (
			List<BarcodeSymbology> pFindBarcodeTypes, string pIndexName, string pDirectoryPath, bool pDeletePreviousResults, 
			string pBarCodePrefixType, string pSetPrefix, string pItemPrefix, bool pUseBasicExcel)
		{
			_UseBasicExcel = pUseBasicExcel;

			ReportProgress ("Inicializando");

			_IndexName = pIndexName;

			R = new DbReader ("DB", "20");

			W = new DbWriter ("DB", "20");

			_BarCodePrefixType = pBarCodePrefixType;
			_SetPrefix = pSetPrefix;
			_ItemPrefix = pItemPrefix;

			_FindBarcodeTypes = pFindBarcodeTypes;

			if (pDeletePreviousResults)
			{
				ReportProgress ("Borrando resultados previos");
				
				DeleteResults ();
			}

			if (!pDirectoryPath.EndsWith (Path.DirectorySeparatorChar.ToString ()))
			{
				pDirectoryPath += Path.DirectorySeparatorChar;
			}

			_DirectoryPath = pDirectoryPath;
		}


		public void Generate 
		(
			bool pDetectBarCodes, bool pOnlyFirstByFolder,
			List<string> pValidExtensions,
			bool pUseLeadtools, bool pTakeOnlyFirst, 
			bool pUseWatcher
		)
		{
			_OnlyFirstByFolder = pOnlyFirstByFolder;

			_DetectBarCodes = pDetectBarCodes;
			
			_ValidExtensions = pValidExtensions;

			_TakeOnlyFirst = pTakeOnlyFirst;

			_UseLeadtools = pUseLeadtools;

			
			try
			{
				ReportProgress("Revisando avance anterior");

				_PreviousAdvance = GetFilesTable ();

				Start(ESF.General.FileHelper.GetFileCount(_DirectoryPath, _ValidExtensions.ToArray())); 
				
				if (!DataHelper.IsEmpty(_PreviousAdvance))
				{
					_PreviousAdvance.PrimaryKey = new DataColumn [] { _PreviousAdvance.Columns ["FileName"] };

					InitializeReadyCount(_PreviousAdvance.Rows.Count);
				}

				_FSW = FileHelper.GenerateFSW (_DirectoryPath, FSW_Changed, FSW_Created);
				_FSW.NotifyFilter = NotifyFilters.LastWrite;
				_FSW.EnableRaisingEvents = pUseWatcher;

				ESF.General.FileHelper.ExecuteInDirectoryFiles(_DirectoryPath, AddToIndex, _ValidExtensions.ToArray(), pCTS: CancelTokenSource);
			}
			catch (OperationCanceledException cex)
			{
				Log.Error (cex);
			}
			finally
			{
				Stop();
			}
		}

		#endregion
		

		#region Metodos
		
		private bool IsValidExtension (string pExtension)
		{
			return (TextHelper.IsIn (pExtension, _ValidExtensions));
		}


		private void AddToIndex (FileInfo pFile, object [] pParams)
		{
			Dictionary<BarcodeSymbology, List<string>> barCodes = new Dictionary<BarcodeSymbology,List<string>> ();
			
			string tempPath;

			int pageCount = 1;

			IndexElement currentItem;

			Stopwatch swLocal;


			if (ExistsFileRegister (pFile))
			{
				return;
			}

			swLocal = new Stopwatch ();

			currentItem = new IndexElement ();
			

			swLocal.Start ();

			currentItem.FileInfo = pFile;

			
			try
			{
				if (pFile.Extension.ToUpper() == ".PDF")
				{
					pageCount = PDFHelper.GetItemCount (pFile.FullName);
				} 
				
				
				if (_DetectBarCodes)
				{
					// Es un PDF
					if (pFile.Extension.ToUpper() == ".PDF")
					{
						tempPath = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ());

						PDFHelper.ExtractImagesFromPDF (pFile.FullName, tempPath);

						foreach (FileInfo file in new DirectoryInfo (tempPath).GetFiles ())
						{
							GetBarCodesFromImage (ref barCodes, file.FullName, out pageCount);
						}

						FileHelper.DeleteDirectory (tempPath);
					}
					else
					{
						GetBarCodesFromImage (ref barCodes, pFile.FullName, out pageCount);
					}
				}

				
				currentItem.FolderFileCount = pFile.Directory.EnumerateFiles ().Count ();

				currentItem.PageCount = pageCount;

				currentItem.BarCodes = barCodes;

				IncrementReadyCount ();
			}
			catch (Exception pEx)
			{
				pEx.Data.Add ("File", pFile.FullName);

				Log.Error(pEx);

				IncrementErrorCount (pEx);

				currentItem.Exception = pEx;
			}
			finally
			{
				swLocal.Stop ();

				currentItem.ProcessingTimeMs = swLocal.ElapsedMilliseconds;

				Register (currentItem);

				ReportProgress (pItemElapsedMs: swLocal.ElapsedMilliseconds);
			}
		}

		#endregion
	}
}
